﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "DockManagerImpl.h"
#include "IApplication.h"
#include "IApplicationWindow.h"
#include "IUiManager.h"
#include "IMainWindow.h"
#include "DebugMessage.h"
#include <QMainWindow>

#include "IPropertyWidget.h"
#include "DockImpl.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;
using namespace std;

//属性面板的标题
#define PROPERTY_PANEL_TITLE L"属性面板"

DockManagerImpl::DockManagerImpl(IApplicationWindow* mainWindow)
    : m_pIMainWindow(mainWindow)
{
}

DockManagerImpl::~DockManagerImpl()
{
}

OwnerPtr<IDock> gcmp::DockManagerImpl::CreateDock(const std::wstring & name, const std::wstring & title) const
{
    QWidget* parent = nullptr;
    if (IMainWindow* pMainWindow = IMainWindow::GetMainWindow())
    {
        parent = QWidget::find((WId)pMainWindow->GetApplicationWindowId());
    }
    return NEW_AS_OWNER_PTR(DockImpl, name, title, parent);
}

void DockManagerImpl::AddDock(OwnerPtr<IDock> opDock, DockArea area, DockOrientation orientation)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(opDock, L"opDock是空指针",L"GDMPLab",L"2024-03-30");

    const wstring& dockName = opDock->GetName();
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_nameToIDockMap.find(dockName) == m_nameToIDockMap.end(), dockName + L"： Dock名已经存在！",L"GDMPLab",L"2024-03-30");

    QMainWindow* pQMainWindow = dynamic_cast<QMainWindow*>(m_pIMainWindow);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pQMainWindow, L"pQMainWindow是空指针",L"GDMPLab",L"2024-03-30");
    QDockWidget* pQDockWidget = dynamic_cast<QDockWidget*>(opDock.get());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pQDockWidget, L"pQDockWidget是空指针",L"GDMPLab",L"2024-03-30");

    m_nameToIDockMap[dockName] = opDock.get();
    m_qDockWidgetToIDockMap[pQDockWidget] = opDock.get();

    Qt::DockWidgetArea qArea = GetQtDockArea(area);
    Qt::Orientation qOrientation = GetQtOrientation(orientation);
    TRANSFER_OWNERSHIP_TO_THIRD_PARTY(opDock);
    pQMainWindow->addDockWidget(qArea, pQDockWidget, qOrientation);
}

void DockManagerImpl::DeleteDock(const std::wstring& name)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(name != IPropertyWidget::GetTypeName(), L"不能删除属性面板",L"GDMPLab",L"2024-03-30");

    IDock* pDock = GetDock(name);
    if (!pDock)
        return;
    
    QMainWindow* pQMainWindow = dynamic_cast<QMainWindow*>(m_pIMainWindow);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pQMainWindow, L"pQMainWindow是空指针",L"GDMPLab",L"2024-03-30");
    QDockWidget* pQDockWidget = dynamic_cast<QDockWidget*>(pDock);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pQDockWidget, L"pQDockWidget是空指针",L"GDMPLab",L"2024-03-30");

    pQMainWindow->removeDockWidget(pQDockWidget);
    m_qDockWidgetToIDockMap.erase(pQDockWidget);
    m_nameToIDockMap.erase(name);
}

IDock* DockManagerImpl::GetDock(const std::wstring& name)
{
    auto search = m_nameToIDockMap.find(name);
    return (search != m_nameToIDockMap.end()) ? search->second : nullptr;
}

void DockManagerImpl::ResizeDocks(const std::vector<IDock*>& docks, const std::vector<int>& sizes, DockOrientation orientation)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(docks.size() == sizes.size(), L"docks和sizes个数不相等",L"GDMPLab",L"2024-03-30");

    QMainWindow* pQMainWindow = GetQMainWindow();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pQMainWindow, L"pQMainWindow是空指针",L"GDMPLab",L"2024-03-30");

    QList<QDockWidget*> qDockWidgets;
    QList<int> qDockSizes;
    for (int i = 0; i < qDockWidgets.size(); ++i)
    {
        QDockWidget* pQDockWidget = GetQDockWidget(docks[i]);
        DBG_WARN_AND_CONTINUE_UNLESS(pQDockWidget, L"pQDockWidget是空指针",L"GDMPLab",L"2024-03-30");
        qDockWidgets.append(pQDockWidget);
        qDockSizes.append(sizes[i]);
    }

    Qt::Orientation qOrientation = GetQtOrientation(orientation);

    pQMainWindow->resizeDocks(qDockWidgets, qDockSizes, qOrientation);
}

void DockManagerImpl::SplitDock(IDock *pFirstDock, IDock *pSecondDock, DockOrientation orientation)
{
    QMainWindow* pQMainWindow = GetQMainWindow();
    QDockWidget* pFirstQDock = GetQDockWidget(pFirstDock);
    QDockWidget* pSecondQDock = GetQDockWidget(pSecondDock);

    DBG_WARN_AND_RETURN_VOID_UNLESS(pQMainWindow, L"pQMainWindow是空指针",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_VOID_UNLESS(pFirstQDock, L"pFirstQDock是空指针",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_VOID_UNLESS(pSecondQDock, L"pSecondQDock是空指针",L"GDMPLab",L"2024-03-30");

    Qt::Orientation qOrientation = GetQtOrientation(orientation);

    pQMainWindow->splitDockWidget(pFirstQDock, pSecondQDock, qOrientation);
}

std::vector<IDock*> DockManagerImpl::TabifiedDocks(IDock* pDock) const
{
    std::vector<IDock*> docks;

    QMainWindow* pQMainWindow = GetQMainWindow();
    QDockWidget* pQDockWidget = GetQDockWidget(pDock);

    DBG_WARN_AND_RETURN_UNLESS(pQMainWindow, docks, L"pQMainWindow是空指针",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_UNLESS(pQDockWidget, docks, L"pQDockWidget是空指针",L"GDMPLab",L"2024-03-30");

    QList<QDockWidget*> dockWidgets = pQMainWindow->tabifiedDockWidgets(pQDockWidget);
    for (auto pWidget : dockWidgets)
    {
        auto search = m_qDockWidgetToIDockMap.find(pWidget);
        DBG_WARN_AND_CONTINUE_UNLESS(search != m_qDockWidgetToIDockMap.end(), L"m_qDockWidgetToIDockMap里没有要找的东西",L"GDMPLab",L"2024-03-30");
        docks.push_back(search->second);
    }
    return docks;
}

void DockManagerImpl::TabifyDock(IDock* firstDock, IDock* secondDock)
{
    QMainWindow* pQMainWindow = GetQMainWindow();
    QDockWidget* pFirstQDock = GetQDockWidget(firstDock);
    QDockWidget* pSecondQDock = GetQDockWidget(secondDock);

    DBG_WARN_AND_RETURN_VOID_UNLESS(pQMainWindow, L"pQMainWindow是空指针",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_VOID_UNLESS(pFirstQDock, L"pFirstQDock是空指针",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_VOID_UNLESS(pSecondQDock, L"pSecondQDock是空指针",L"GDMPLab",L"2024-03-30");

    pQMainWindow->tabifyDockWidget(pFirstQDock, pSecondQDock);
}

QMainWindow* DockManagerImpl::GetQMainWindow() const
{
    return dynamic_cast<QMainWindow*>(m_pIMainWindow);
}

QDockWidget* DockManagerImpl::GetQDockWidget(IDock* pDock) const
{
    return dynamic_cast<QDockWidget*>(pDock);
}

Qt::Orientation DockManagerImpl::GetQtOrientation(DockOrientation orientation) const
{
    return (orientation == DockOrientation::Horizontal) ? Qt::Horizontal : Qt::Vertical;
}

Qt::DockWidgetArea DockManagerImpl::GetQtDockArea(DockArea area) const
{
    Qt::DockWidgetArea qtDockArea;
    switch (area)
    {
    case gcmp::DockArea::Left:
        qtDockArea = Qt::DockWidgetArea::LeftDockWidgetArea;
        break;
    case gcmp::DockArea::Right:
        qtDockArea = Qt::DockWidgetArea::RightDockWidgetArea;
        break;
    case gcmp::DockArea::Top:
        qtDockArea = Qt::DockWidgetArea::TopDockWidgetArea;
        break;
    case gcmp::DockArea::Bottom:
        qtDockArea = Qt::DockWidgetArea::BottomDockWidgetArea;
        break;
    case gcmp::DockArea::All:
        qtDockArea = Qt::DockWidgetArea::AllDockWidgetAreas;
        break;
    case gcmp::DockArea::None:
        qtDockArea = Qt::DockWidgetArea::NoDockWidgetArea;
        break;
    default:
        break;
    }
    return qtDockArea;
}

IPropertyWidget* DockManagerImpl::GetPropertyWidget()
{
    IUiManager *pUiManager = IUiManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiManager, L"pUiManager为空",L"GDMPLab",L"2024-03-30");
    IDockManager* dockManager = pUiManager->GetDockManager();
    IDock* pDock = dockManager->GetDock(IPropertyWidget::GetTypeName());
    if (pDock)
    {
        return dynamic_cast<IPropertyWidget*>(pDock->GetWidget());
    }

    return nullptr;
}

void DockManagerImpl::ShowAllDockPane()
{
    IUiManager *pUiManager = IUiManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiManager, L"pUiManager为空",L"GDMPLab",L"2024-03-30");
    IDockManager* dockManager = pUiManager->GetDockManager();
    DBG_WARN_AND_RETURN_VOID_UNLESS(dockManager, L"dockManager是空指针",L"GDMPLab",L"2024-03-30");
    for (auto iter : m_nameToIDockMap)
    {
        if (iter.second)
        {
            iter.second->Show();
        }
    }
    
}

void DockManagerImpl::HideAllDockPane()
{
    IUiManager *pUiManager = IUiManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiManager, L"pUiManager为空",L"GDMPLab",L"2024-03-30");
    IDockManager* dockManager = pUiManager->GetDockManager();
    DBG_WARN_AND_RETURN_VOID_UNLESS(dockManager, L"dockManager是空指针",L"GDMPLab",L"2024-03-30");
    for (auto iter : m_nameToIDockMap)
    {
        if (iter.second)
        {
            iter.second->Hide();
        }
    }
}

bool gcmp::DockManagerImpl::IsDockable(const std::wstring & name) const
{
    const auto search = m_nameToIDockMap.find(name);
    if (search == m_nameToIDockMap.end())
    {
        return false;
    }
    const IDock * pDock = search->second;
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDock, L"pDock是空指针",L"GDMPLab",L"2024-03-30");
    const QDockWidget * pQDock = dynamic_cast<const QDockWidget*>(pDock);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pQDock, L"pQDock是空指针",L"GDMPLab",L"2024-03-30");
    return pQDock->features() == QDockWidget::AllDockWidgetFeatures;
}

bool gcmp::DockManagerImpl::SetIsDockable(const std::wstring & name, bool isDockable)
{
    const auto search = m_nameToIDockMap.find(name);
    if (search == m_nameToIDockMap.end())
    {
        return false;
    }
    IDock * pDock = search->second;
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDock, L"pDock是空指针",L"GDMPLab",L"2024-03-30");
    QDockWidget * pQDock = dynamic_cast<QDockWidget*>(pDock);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pQDock, L"pQDock是空指针",L"GDMPLab",L"2024-03-30");
    if (isDockable)
    {
        pQDock->setFeatures(QDockWidget::AllDockWidgetFeatures);
    }
    else
    {
        pQDock->setFeatures(QDockWidget::NoDockWidgetFeatures);
    }
    return true;
}

bool gcmp::DockManagerImpl::RemoveDockTitleBar(const std::wstring & name)
{
    const auto search = m_nameToIDockMap.find(name);
    if (search == m_nameToIDockMap.end())
    {
        return false;
    }
    IDock * pDock = search->second;
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDock, L"pDock是空指针",L"GDMPLab",L"2024-03-30");
    QDockWidget * pQDock = dynamic_cast<QDockWidget*>(pDock);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pQDock, L"pQDock是空指针",L"GDMPLab",L"2024-03-30");
    pQDock->setTitleBarWidget(NEW_AS_QT(QWidget));
    pQDock->setFeatures(QDockWidget::NoDockWidgetFeatures);
    return true;
}

void gcmp::DockManagerImpl::UpdateAllDockStatus()
{
    for (auto iter : m_nameToIDockMap)
    {
        IDock* pDock = iter.second;
        if (!pDock)
            continue;

        if (pDock->IsHidden())
            continue;

        IWidget* pWidget = pDock->GetWidget();
        DBG_WARN_AND_CONTINUE_UNLESS(pWidget, L"pWidget是空指针",L"GDMPLab",L"2024-03-30");
        
        pWidget->UpdateStatus();
    }
}
